package main

/*

#include<stdio.h>
#include<stdlib.h>
#include<sys/ioctl.h>
#include<linux/hdreg.h>
#include<sys/fcntl.h>
#include <string.h>

#define LENGTH 32
char* GetSerial(){
  struct hd_driveid id;
  int fd = open("/dev/sda", O_RDONLY|O_NONBLOCK);
  if(fd<0){
    perror("/dev/sda");
    return;
    }
  if(!ioctl(fd, HDIO_GET_IDENTITY, &id)){
      //printf("%s\n", id.serial_no);
	char* m = malloc(LENGTH*sizeof(char));
	sprintf(m, "%s", id.serial_no);
	return m;
    }
  return 0;
}

*/
import "C"

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"
	"unsafe"
)

func GenericMachineCode() (bool, string) {
	if C.GetSerial() == nil {
		log.Fatal("获取机器码失败")
	}
	result := C.GetSerial()
	DiskSerialNumber := C.GoString(result)
	C.free(unsafe.Pointer(result))

	CPUSerialNumber := ""
	CMDResM, ResDataM := ExecCommand("/bin/sh", "-c", `dmidecode -t 4 | grep ID`)
	if CMDResM == false {
		log.Fatal("CMDResM is false")
		return false, "CMDResM is false"
	}
	t_index := strings.Index(ResDataM[1], ":")
	CPUSerialNumber = strings.Replace(ResDataM[1][t_index+1:], " ", "", -1)

	if DiskSerialNumber == "" || CPUSerialNumber == "" {
		log.Fatal("获取机器码失败")
		return false, "获取机器码失败"
	}
	// make machine id
	o_machine_code := strings.Replace(DiskSerialNumber+CPUSerialNumber, "\n", "", -1)
	// generate one hash encode times for every machine
	encode_times := 0
	if reg, err := regexp.Compile(`\d`); err != nil {
		encode_times = len(SecreteKey)
	} else {
		tmp_str := ""
		for _, v := range reg.FindAllStringSubmatch(o_machine_code, -1) {
			tmp_str += v[0]
		}
		encode_times, _ = strconv.Atoi(tmp_str)
	}
	for encode_times > 500 {
		encode_times = encode_times / len(SecreteKey)
	}

	for i := 0; i < encode_times; i++ {
		o_machine_code = Get16MD5Encode(o_machine_code)
	}
	machine_code := strings.ToUpper(o_machine_code)

	// 创建active record
	if !CheckFileIsExist(RecordActive) {
		f, err := os.Create(RecordActive)
		defer f.Close()
		if err != nil {
			log.Fatal("license failed")
		}
	}

	return true, machine_code
}

func GenerateLicense(active string) bool {
	//_, _, o_active := GetTimeFromFile()
	//if active == o_active {
	//	log.Fatal("active again?")
	//}
	// 验证激活码
	ok, expire_time, api_info := VerifyActiveCode(active)
	if !ok {
		log.Fatal("active verify failed")
	}
	//fmt.Println("check flag")
	// 验证flag
	if !CheckFlag() {
		log.Fatal("license failed")
	}
	//fmt.Println("create license")
	// 创建license
	unix := time.Now().Unix()

	// api_info对称加密完成
	secret_key := GetMD5Encode(SecreteKey)
	api_info, ok = AESEncrypt([]byte(secret_key), api_info)
	if !ok {
		log.Fatal("api_info encrypt is failed")
	}
	var expire_time64 int64
	if expire_time < 0 {
		expire_time64 = int64(expire_time)
	} else {
		expire_time64 = unix + int64(expire_time)
	}
	SaveTimeToFile(unix, expire_time64, api_info)
	fmt.Println("Ok")
	return true
}

func SaveTimeToFile(unix int64, expire_time64 int64, api_info string) {
	us := strconv.FormatInt(unix, 10)
	ues := strconv.FormatInt(expire_time64, 10)
	aes_now_time := GenerateAESTime(us)
	aes_expire_time := GenerateAESTime(ues)

	CreateUpdateFile(aes_now_time, LicensePath)
	md5_res, err := CalcFileMD5(LicensePath)
	if err != nil {
		log.Fatal("license md5 failed")
	}
	md5_res2, err := CalcFileMD5(RecordActive)
	if err != nil {
		log.Fatal("license md5 failed")
	}
	//fmt.Println("api_info is ", api_info)
	//fmt.Println("md5_res", Get16MD5Encode(md5_res))
	//fmt.Println("md5_res2", Get16MD5Encode(md5_res2))
	//fmt.Println("aes_et", aes_expire_time)
	//fmt.Println("aes_nt", aes_now_time)
	sub_file_info := Get16MD5Encode(md5_res) + Get16MD5Encode(md5_res2) + aes_expire_time + "\n" + api_info
	CreateUpdateFile(sub_file_info, MD5Path)
}

func AppendFlagToBashrc() {
	// 通过在bashrc中写入flag形式判定文件，bashrc这个文件可以更改为任意的
	f, err := os.OpenFile("/root/.bashrc", os.O_RDWR|os.O_APPEND, 0777)
	defer f.Close()
	if err != nil {
		//fmt.Println(err)
		log.Fatal("license failed")
	}
	w := bufio.NewWriter(f)
	if _, err := w.WriteString("# System Exp Environment\nexport SYSENV = \"/etc/environment\"\n"); err != nil {
		log.Fatal("license failed")
	}
	w.Flush()
}
